#pragma once
#include<iostream>
#include<vector>
#include<queue>
#include<string.h>
#include<functional>
#include "Log.hpp"
#include "Thread.hpp"
#include "LockGuard.hpp"
#include"Task.hpp"
static const int defaultnum=5;
class ThreadData
{
public:
    ThreadData(const std::string &name) : threadname(name)
    {
    }
    ~ThreadData()
    {
    }

public:
    std::string threadname;
};
template<class T>
class ThreadPool
{
private:
ThreadPool(int threadnum=defaultnum):_thread_num(threadnum)
{
    pthread_mutex_init(&_mutex,nullptr);
    pthread_cond_init(&_cond,nullptr);
    for(int i=0;i<_thread_num;i++)
    {
        std::string threadname="Thread -";
        threadname+=std::to_string(i+1);
        ThreadData td(threadname);
        // Thread<ThreadData> t(threadname,std::bind(&ThreadPool<T>::ThreadRun,this,std::placeholders::_1),td);
        // _threads.push_back(t);
        _threads.emplace_back(threadname,\
        std::bind(&ThreadPool<T>::ThreadRun,\
        this,std::placeholders::_1),td);
        lg.LogMessage(Info,"%s is created...\n",threadname.c_str());
    }
}
ThreadPool(const ThreadPool<T>&td)=delete;
const ThreadPool<T>&operator=(const ThreadPool<T>)=delete;

public:
static ThreadPool<T> *GetInstance()
{
    if (instance == nullptr)
        {
            LockGuard lockguard(&sig_lock);
            if (instance == nullptr)
            {
                lg.LogMessage(Info, "创建单例成功...\n");
                instance = new ThreadPool<T>();
            }
        }
     return instance;
}

bool Start()
{
    for(auto&thread:_threads)
    {
        thread.Start();
        lg.LogMessage(Info,"%s is running...\n",thread.ThreadName().c_str());
    }
    return true;
}
void ThreadRun(ThreadData&td)
{
    while(true)
    {
       T t;
       {
        LockGuard lockguard(&_mutex);
        while(_q.empty())
        {
            ThreadWait(td);
            lg.LogMessage(Debug,"have task,%s is walking...\n",td.threadname.c_str());
        }
        t=_q.front();
        _q.pop();
       }
        t();
       lg.LogMessage(Debug, "%s handler task %s done, result is : %s\n",
                          td.threadname.c_str(), t.PrintTask().c_str(), t.PrintResult().c_str());
    }
}
void ThreadWait(const ThreadData&td)
{
    lg.LogMessage(Debug,"no task, %s is sleeping... \n",td.threadname.c_str());
    pthread_cond_wait(&_cond,&_mutex);
}
void ThreadWakeUp()
{
  
    pthread_cond_signal(&_cond);
}
void Push(T&in)
{
    lg.LogMessage(Debug,"Other thread pushed a task,task is %s\n",in.PrintTask().c_str());
    LockGuard lockguard(&_mutex);
    _q.push(in);
    ThreadWakeUp();

}
~ThreadPool()
{
    pthread_mutex_destroy(&_mutex);
    pthread_cond_destroy(&_cond);
}
void Wait()
{
    for(auto &thread:_threads)
    {
        thread.Join();
    }
}
private:
std::queue<T> _q;
std::vector<Thread<ThreadData>> _threads;
int _thread_num;
int _task_num;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
// int _thread_num_low_water;  // 3
// int _thread_num_high_water; // 10
// int _task_num_low_water;    // 0
// int _task_num_high_water;   // 30
static ThreadPool<T>*instance;
static pthread_mutex_t sig_lock;
};
template<class T>
ThreadPool<T>*ThreadPool<T>::instance=nullptr;
template<class T>
pthread_mutex_t ThreadPool<T>::sig_lock=PTHREAD_MUTEX_INITIALIZER;
